using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace DarkLordsApprenticeV2
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        public KeyboardState keysCurrent;
        public KeyboardState keysPrevious;
        public bool gamePaused;

        public SpriteFont fontSansSerif;
        public SpriteFont fontSerif;

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Boolean leftMouseDown = false;
        Boolean leftJustPressed = false;
        Boolean leftJustReleased = false;

        Boolean rightMouseDown = false;
        Boolean rightJustPressed = false;
        Boolean rightJustReleased = false;

        Boolean mouseMoved = false;
        int magicStored = 0;
        Vector2 oldMousePoint = new Vector2(0,0);

        enum GameState { Intro, Story, Instructions, Game, GoodEnding, BadEnding };
        GameState prevState = GameState.Intro;
        GameState currentState = GameState.Intro;
        int gameCounter;

        Texture2D pauseSplash;
        StoryHelper storyHelper;
        Background background;
        Apprentice apprentice;
        MagicCircle magicCircle;
        List<Fire> fireList;
        List<Hero> heroList;
        List<Goblin> gobList;
        Boolean hasBodyguard;

        Character auraTest;
        Display display;
        SpellCircle spellCircle;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }


        protected override void Initialize()
        {
            keysCurrent = Keyboard.GetState();
            keysPrevious = keysCurrent;             // initially, have them identical

            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 600;
            graphics.ApplyChanges();

            gameCounter = 0;

            gamePaused = false;                     // game should obviously NOT be paused at start
            storyHelper = new StoryHelper(this, new Vector2(0, 0));
            Components.Add(storyHelper);
            background = new Background(this, new Vector2(0, 0));
            apprentice = new Apprentice(this);
            magicCircle = new MagicCircle(this);
            fireList = new List<Fire>();
            heroList = new List<Hero>();
            gobList = new List<Goblin>();
            hasBodyguard = false;
            display = new Display(this);
            spellCircle = new SpellCircle(this);
            Components.Add(spellCircle);
            auraTest = new Character(this, Vector2.Zero, "aura", 15, 100, 5);
            base.Initialize();
        }


        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // Load fonts
            //fontSansSerif = Content.Load<SpriteFont>("Lithos Pro");
            //fontSerif = Content.Load<SpriteFont>("Cambria");

            pauseSplash = Content.Load<Texture2D>("PauseScreen");
        }


        protected override void Update(GameTime gameTime)
        {
            Random rand = new Random();

            auraTest.Update(gameTime);

            // Get keys pressed
            keysCurrent = Keyboard.GetState();      // get fresh input set

            // If 'P' has been pressed, toggle pause
            if (keysCurrent.IsKeyUp(Keys.P) && keysPrevious.IsKeyDown(Keys.P))
            {
                gamePaused = !gamePaused;
                auraTest.SetSeq(15, 10);
            }

            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // Mouse State updating
            MouseState m = Mouse.GetState();
            if (m.LeftButton == ButtonState.Pressed)
            {
                if (leftMouseDown)
                {
                    leftJustPressed = false;
                }
                else
                {
                    leftJustPressed = true;
                    leftMouseDown = true;
                }
            }
            else if (m.LeftButton == ButtonState.Released)
            {
                if (leftMouseDown)
                {
                    leftJustReleased = true;
                    leftMouseDown = false;
                }
                else
                {
                    leftJustReleased = false;
                }
            }

            if (m.RightButton == ButtonState.Pressed)
            {
                if (rightMouseDown)
                {
                    rightJustPressed = false;
                }
                else
                {
                    rightJustPressed = true;
                    rightMouseDown = true;
                }
            }
            else if (m.RightButton == ButtonState.Released)
            {
                if (rightMouseDown)
                {
                    rightJustReleased = true;
                    rightMouseDown = false;
                }
                else
                {
                    rightJustReleased = false;
                }
            }



            if (m.X == oldMousePoint.X && m.Y == oldMousePoint.Y)
            {
                mouseMoved = false;
            }
            else
            {
                mouseMoved = true;
                if (leftMouseDown)
                {
                    magicStored = 0;
                }
            }

            oldMousePoint = new Vector2(m.X, m.Y);




            // game loop stuff depending on the current GameState
            switch (currentState)
            {
                case GameState.Intro:
                    if (leftJustReleased)
                    {
                        prevState = currentState;
                        currentState = GameState.Story;
                    }
                    break;

                case GameState.Story:
                    if (leftJustReleased)
                    {
                        prevState = currentState;
                        currentState = GameState.Instructions;
                    }
                    break;

                case GameState.Instructions:
                    if (leftJustReleased)
                    {
                        prevState = currentState;
                        currentState = GameState.Game;
                    }
                    break;

                case GameState.Game:
                    if (prevState == GameState.Instructions)    // initialize game
                    {
                        Components.Add(background);
                        Components.Add(apprentice);
                        Components.Add(magicCircle);
                        Components.Add(display);
                        //Components.Add(auraTest);
                        //makeHero(400f, .5f, 100f);
                        
                        prevState = currentState;
                    }

                    if (gameCounter % Math.Round(600f/apprentice.GetEvilnessLevel()) == 0)
                    {
                        makeHero(400f, 5f, .5f, 200f);
                    }
                    if (gameCounter % Math.Round(500f / apprentice.GetEvilnessLevel()) == 0)
                    {
                        makeHero((float)(200f + 500f * rand.NextDouble()), 5f, .5f, 200f);
                    }

                    
                    if (leftJustPressed || rightJustPressed)
                    {
                        apprentice.SwitchToCasting();
                    }
                    if (leftJustReleased || rightJustReleased)
                    {
                        apprentice.SwitchToIdle();
                        if (leftJustReleased)
                        {
                            makeFire(new Vector2(m.X, m.Y), 50 + magicStored);
                        }
                        if (rightJustReleased)
                        {
                            summon(new Vector2(m.X, m.Y), magicStored);
                        }
                    }
                    if (leftMouseDown && mouseMoved)
                    {
                        makeFire(new Vector2(m.X, m.Y), 50);
                    }
<<<<<<< .mine
                    display.UpdateDisplay(apprentice.GetCurrentMagic(), apprentice.GetMaxMagic(), apprentice.GetEvilnessLevel());

                    // Calculate position, life state, etc. for all moving characters on screen
                    foreach (Hero h in heroList)
                    {
                        if (h.GetHP() > 0 && h.Position.X > 650 && h.Position.Y > 500)
                        {
                            prevState = currentState;
                            currentState = GameState.BadEnding;
                            Components.Remove(storyHelper);
                            Components.Add(storyHelper);
                            Components.Remove(background);
                            Components.Remove(apprentice);
                            Components.Remove(magicCircle);
                            Components.Remove(display);
                        }
                        foreach (Fire f in fireList)
                        {
                            Vector2 diff = f.Position - h.Position;
                            //float dist = diff.Length();
                            if (Math.Abs(diff.X) < (f.GetWidth() + h.GetWidth()) / 2 && Math.Abs(diff.Y) < (f.GetWidth() / 4 + h.GetWidth() / 4) / 2)
                            {
                                h.LoseHP(f.GetIntensity() / 100f);
                                if (h.GetHP() <= 0)
                                {
                                    h.SwitchToToasty();
                                }
                            }
                        }
                        foreach (Goblin g in gobList)
                        {
                            Vector2 diff = g.Position - h.Position;
                            float dist = diff.Length();
                            if (h.GetHP() > 0 && dist < g.GetDistanceToTarget())
                            {
                                g.SetTarget(h.Position);
                            }
                            if (Math.Abs(diff.X) < (g.GetWidth() + h.GetWidth()) / 3 && Math.Abs(diff.Y) < (g.GetWidth() / 4 + h.GetWidth() / 4) / 2)
                            {
                                if (g.GetHP() > 0)
                                {
                                    h.LoseHP(g.GetAttack());
                                }
                                if (h.GetHP() <= 0)
                                {
                                    if (diff.X < 0)
                                    {
                                        h.sendFlying(new Vector2(10, -20));
                                        g.Position.X += -50 * g.scale;
                                    }
                                    else
                                    {
                                        h.sendFlying(new Vector2(-10, -20));
                                        g.Position.X += 50 * g.scale;
                                    }
                                }

                                if (h.GetHP() > 0)
                                {
                                    g.LoseHP(h.GetAttack());
                                }
                                if (g.GetHP() <= 0)
                                {
                                    g.SwitchToSlain();
                                }
                            }
                        }
                    }

                    if (leftMouseDown && apprentice.GetCurrentMagic() > 0)
                    {
                        magicStored++;
                        apprentice.SpendMagic();
                    }

                    if (rightMouseDown && apprentice.GetCurrentMagic() > 0)
                    {
                        magicStored++;
                        apprentice.SpendMagic();
                        if (!hasBodyguard && m.X > 380 && m.X < 500 && m.Y > 560)
                        {
                            if (magicStored > 50)
                            {
                                magicCircle.SwitchToGreen();
                            }
                            else
                            {
                                magicCircle.SwitchToIdle();
                            }
                        }
                    }

                    if (!leftMouseDown && !rightMouseDown)
                    {
                        magicStored = 0;
                    }

                    gameCounter++;
=======
                    display.UpdateDisplay(apprentice.GetCurrentMagic(), apprentice.GetMaxMagic(), apprentice.GetEvilnessLevel());
>>>>>>> .r34
                    break;

                case GameState.GoodEnding:
                    if (leftJustReleased)
                    {
                        prevState = currentState;
                        currentState = GameState.Intro;
                    }
                    break;

                case GameState.BadEnding:
                    if (leftJustReleased)
                    {
                        prevState = currentState;
                        currentState = GameState.Intro;
                    }
                    break;
            }

            // if the current GameState is different from the previous one
            // update stuff goes here
            if (currentState != prevState)
            {
                if (prevState == GameState.Game)
                {
                    storyHelper.Visible = true;
                }

                switch (currentState) {
                    case GameState.Intro:
                        storyHelper.SwitchToIntro();
                        break;

                    case GameState.Story:
                        storyHelper.SwitchToStory();
                        break;

                    case GameState.Instructions:
                        storyHelper.SwitchToInstructions();
                        break;

                    case GameState.Game:
                        break;

                    case GameState.GoodEnding:
                        storyHelper.SwitchToGoodEnding();
                        Fire[] fireArray1 = fireList.ToArray();
                        for (int i = 0; i < fireArray1.Length; i++)
                        {
                            Components.Remove(fireArray1[i]);
                            fireList.Remove(fireArray1[i]);
                            
                        }

                        Hero[] heroArray1 = heroList.ToArray();
                        for (int i = 0; i < heroArray1.Length; i++) {
                           
                            Components.Remove(heroArray1[i]);
                            heroList.Remove(heroArray1[i]);
                           
                        }

                        Goblin[] gobArray1 = gobList.ToArray();
                        for (int i = 0; i < gobArray1.Length; i++)
                        {
                            Components.Remove(gobArray1[i]);
                            gobList.Remove(gobArray1[i]);
                        }
                        break;

                    case GameState.BadEnding:
                        storyHelper.SwitchToBadEnding();
                        Fire[] fireArray2 = fireList.ToArray();
                        for (int i = 0; i < fireArray2.Length; i++)
                        {
                            Components.Remove(fireArray2[i]);
                            fireList.Remove(fireArray2[i]);
                            
                        }

                        Hero[] heroArray2 = heroList.ToArray();
                        for (int i = 0; i < heroArray2.Length; i++) {
                           
                            Components.Remove(heroArray2[i]);
                            heroList.Remove(heroArray2[i]);
                           
                        }

                        Goblin[] gobArray2 = gobList.ToArray();
                        for (int i = 0; i < gobArray2.Length; i++)
                        {
                            Components.Remove(gobArray2[i]);
                            gobList.Remove(gobArray2[i]);
                        }
                        break;
                }
            }

            // Things to do @ end of each frame
            keysPrevious = keysCurrent;

            Fire[] fireArray = fireList.ToArray();
            for (int i = 0; i < fireArray.Length; i++)
            {
                if (fireArray[i].IsDead())
                {
                    Components.Remove(fireArray[i]);
                    fireList.Remove(fireArray[i]);
                }
            }

            Hero[] heroArray = heroList.ToArray();
            for (int i = 0; i < heroArray.Length; i++) {
                if (heroArray[i].IsDead()) {
                    apprentice.GainEXP(1);
                    Components.Remove(heroArray[i]);
                    heroList.Remove(heroArray[i]);
                }
            }

            Goblin[] gobArray = gobList.ToArray();
            for (int i = 0; i < gobArray.Length; i++)
            {
                if (gobArray[i].IsDead())
                {
                    if (gobArray[i].IsBodyguard())
                    {
                        hasBodyguard = false;
                    }
                    Components.Remove(gobArray[i]);
                    gobList.Remove(gobArray[i]);
                }
            }

            Components.Remove(spellCircle);
            spellCircle.setPosition(new Vector2(m.X, m.Y));
            Components.Add(spellCircle);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // Draw everything in here
            spriteBatch.Begin();
            base.Draw(gameTime);
            if (gamePaused)
            {
                //spriteBatch.DrawString(fontSerif, "GAME PAUSED", new Vector2(300, 400), Color.White);
                spriteBatch.Draw(pauseSplash, Vector2.Zero, Color.White);
            }
            spriteBatch.Draw(auraTest.image, auraTest.position, auraTest.aniMask, Color.White);
            spriteBatch.End();
        }

        private void makeFire(Vector2 pos, int intensity)
        {
            if ((apprentice.GetCurrentMagic() > 1 || magicStored > 0) && pos.X > 100 && pos.X < 700 && pos.Y > 200 && pos.Y < 450)
            {
                var fire = new Fire(this, pos, apprentice.GetEvilnessLevel(), intensity);
                fireList.Add(fire);
                Components.Add(fire);
            }
        }

        private void makeHero(float initX, float atk, float spd, float hp)
        {
            var hero = new Hero(this, new Vector2(initX, 180), atk, spd, hp);
            heroList.Add(hero);
            Components.Add(hero);
        }

        private void summon(Vector2 pos, float magic)
        {
            if (magicStored >= 50)
            {
                if (pos.X > 100 && pos.X < 700 && pos.Y > 200 && pos.Y < 450)
                {
                    var goblin = new Goblin(this, pos, magic/5f, magic/100f, magic*2f,false);
                    gobList.Add(goblin);
                    Components.Add(goblin);
                }
                else if (!hasBodyguard && pos.X > 380 && pos.X < 500 && pos.Y > 560)
                {
                    hasBodyguard = true;
                    var goblin = new Goblin(this, new Vector2(440,580), magic / 5f, magic / 100f, magic * 2f, true);
                    gobList.Add(goblin);
                    Components.Add(goblin);
                    magicCircle.SwitchToIdle();
                }
            }
        }

    }
}
